#pragma once
#include "thread.hpp"
#include "mutex.hpp"
#include "cond.hpp"
#include "log.hpp"
#include <queue>
using namespace mythread;
using namespace mymutex;
using namespace mycond;
using namespace mylog;

// template <typename T>
// class Singleton
// {
//     static T data;

// public:
//     static T *GetInstance()
//     {
//         return &data;
//     }
// };
// template <typename T>
// class Singleton
// {
//     static T *inst;

// public:
//     static T *GetInstance()
//     {
//         if (inst == NULL)
//         {
//             inst = new T();
//         }
//         return inst;
//     }
// };

// // 懒汉模式, 线程安全
// template <typename T>
// class Singleton
// {
//     volatile static T *inst; // 需要设置 volatile 关键字, 否则可能被编译器优化.
//     static std::mutex lock;

// public:
//     static T *GetInstance()
//     {
//         if (inst == NULL)
//         {                // 双重判定空指针, 降低锁冲突的概率, 提⾼性能.
//             lock.lock(); // 使⽤互斥锁, 保证多线程情况下也只调⽤⼀次 new.
//             if (inst == NULL)
//             {
//                 inst = new T();
//             }
//             lock.unlock();
//         }
//         return inst;
//     }
// };

namespace ThreadPool
{
    static int default_num = 5;
    template <typename T>
    class Threadpool
    {
        void Weakup()
        {
            LOG(Level::DEBUG) << "唤醒所有线程";
            _cond.Broadcast();
        }

    public:
        Threadpool(int num = default_num) : _num(num), _runing(false), _sleepnum(0)
        {
            for (int i = 0; i < num; i++)
            {
                _threadpool.emplace_back(
                    [this]()
                    {
                        HandlerTask();
                    });
            }
        }
        static Threadpool<T> *GetInstance()
        {
            if (inc == nullptr)
            {
                LockGroup lockgroup(_lock);

                LOG(Level::DEBUG) << "获取单例....";
                if (inc == nullptr)
                {
                    LOG(Level::DEBUG) << "首次使用单例, 创建之....";
                    inc = new Threadpool<T>();
                    inc->Start();
                }
            }

            return inc;
        }
        void HandlerTask()
        {
            T task;
            while (true)
            {
                LockGroup lgp(_mutex);
                {
                    while (_taskqueue.empty() && _runing)
                    {
                        _sleepnum++;
                        _cond.Wait(_mutex.GetMutex());
                        _sleepnum--;
                    }
                    // 取任务
                    if (_taskqueue.empty())
                    {
                        LOG(Level::DEBUG) << "线程退出";
                        break;
                    }
                    task = _taskqueue.front();
                    _taskqueue.pop();
                }
                // 处理任务
                task();
            }
        }
        void Start()
        {
            _runing = true;
            for (auto &thread : _threadpool)
            {
                thread.Start();
            }
        }
        void Join()
        {
            for (auto &thread : _threadpool)
            {
                thread.Join();
            }
        }
        void Enqueue(T data)
        {
            if (!_runing)
                return;
            LockGroup lgp(_mutex);
            _taskqueue.push(data);
            if (_sleepnum > 0)
            {
                _cond.Signal();
            }
        }
        ~Threadpool()
        {
            Join();
        }
        void Stop()
        {
            _runing = false;
            Weakup();
        }

    private:
        std::vector<Thread> _threadpool; // 线程
        std::queue<T> _taskqueue;        // 任务队列
        Mutex _mutex;                    // 互斥量
        Cond _cond;                      // 条件变量
        int _num;                        // 线程数量
        bool _runing;                    // 运行状态

        int _sleepnum;

        static Threadpool<T> *inc; // 单例指针
        static Mutex _lock;
    };
    template <typename T>
    Threadpool<T> *Threadpool<T>::inc = nullptr;
    template <typename T>
    Mutex Threadpool<T>::_lock;
}
